-
Notifications
You must be signed in to change notification settings - Fork 506
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support richer COM interface hierarchies #1608
Conversation
use std::ffi::*;
use std::sync::*;
use windows::{core::*, Win32::Foundation::*, Win32::System::Com::*};
#[implement(IPersistMemory, IPersist)]
#[derive(Default)]
struct Persist(RwLock<PersistState>);
#[derive(Default)]
struct PersistState {
memory: [u8; 10],
dirty: bool,
}
impl IPersist_Impl for Persist {
fn GetClassID(&self) -> Result<GUID> {
Ok("117fb826-2155-483a-b50d-bc99a2c7cca3".into())
}
}
impl IPersistMemory_Impl for Persist {
fn IsDirty(&self) -> Result<()> {
let reader = self.0.read().unwrap();
if reader.dirty {
Ok(())
} else {
Err(S_FALSE.into())
}
}
fn Load(&self, input: *const c_void, size: u32) -> Result<()> {
unsafe {
let mut writer = self.0.write().unwrap();
if size <= writer.memory.len() as _ {
std::ptr::copy(input, writer.memory.as_mut_ptr() as _, size as _);
writer.dirty = true;
Ok(())
} else {
Err(E_OUTOFMEMORY.into())
}
}
}
fn Save(&self, output: *mut c_void, clear_dirty: BOOL, size: u32) -> Result<()> {
unsafe {
let mut writer = self.0.write().unwrap();
if size <= writer.memory.len() as _ {
std::ptr::copy(writer.memory.as_mut_ptr() as _, output, size as _);
if clear_dirty.as_bool() {
writer.dirty = false;
}
Ok(())
} else {
Err(E_OUTOFMEMORY.into())
}
}
}
fn GetSizeMax(&self) -> Result<u32> {
let reader = self.0.read().unwrap();
Ok(reader.memory.len() as _)
}
fn InitNew(&self) -> Result<()> {
let mut writer = self.0.write().unwrap();
writer.memory = Default::default();
writer.dirty = false;
Ok(())
}
}
fn main() -> Result<()> {
unsafe {
let p: IPersistMemory = Persist::default().into();
assert_eq!(
p.GetClassID()?,
"117fb826-2155-483a-b50d-bc99a2c7cca3".into()
);
// TODO: can't test IsDirty until this is fixed: https://github.com/microsoft/win32metadata/issues/838
assert_eq!(p.GetSizeMax()?, 10);
p.Load(&[0xAA, 0xBB, 0xCC])?;
let mut memory = [0x00, 0x00, 0x00, 0x00];
p.Save(&mut memory, true)?;
assert_eq!(memory, [0xAA, 0xBB, 0xCC, 0x00]);
Ok(())
}
} |
Perhaps something like this: #[interface("0000010c-0000-0000-C000-000000000046")]
pub unsafe trait ICustomPersist : IUnknown {
unsafe fn GetClassID(&self, clsid: *mut GUID) -> HRESULT;
}
#[interface("BD1AE5E0-A6AE-11CE-BD37-504200C10000")]
pub unsafe trait ICustomPersistMemory : ICustomPersist {
unsafe fn IsDirty(&self) -> HRESULT;
unsafe fn Load(&self, input: *const c_void, size: u32) -> HRESULT;
unsafe fn Save(&self, output: *mut c_void, clear_dirty: BOOL, size: u32) -> HRESULT;
unsafe fn GetSizeMax(&self, len: *mut u32) -> HRESULT;
unsafe fn InitNew(&self) -> HRESULT;
} |
As part of #1486, this allows for COM interfaces that inherit from something other than
IUnknown
.This also adds a test with a simple but rich COM hierarchy.